package com.xhsj.user.hr.aspect;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.xhsj.user.hr.system.entity.TbOperationRecords;
import com.xhsj.user.hr.system.mapper.TbOperationRecordsMapper;
import com.xhsj.user.utils.UserUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;

/**
 * @Description OperationAspect
 * @Author suxiaolin
 * @Date 2021/4/27 15:38
 */
@Slf4j
@Aspect
@Order
@Component
public class OperationAspect {

    @Autowired
    private TbOperationRecordsMapper tbOperationRecordsMapper;

    @Pointcut("@annotation(com.xhsj.user.hr.aspect.OperationPointCut)")
    public void pointCut(){

    };

    @Before(value = "pointCut()")
    public void methodBefore(JoinPoint joinPoint) throws Throwable {
    }

    @After(value = "pointCut()")
    public void methodAfter(JoinPoint joinPoint) {
    }

    @AfterReturning(value = "pointCut()",returning = "result")
    public void methodReturning(JoinPoint joinPoint, Object result) {
    }

    @Around(value = "pointCut()")
    public Object methodAround(ProceedingJoinPoint joinPoint) throws Throwable {
        Object proceed = joinPoint.proceed();
        String fullName = UserUtils.getLoginAppUser().getFullName();
        Long userId = UserUtils.getLoginAppUser().getUserId();

        CompletableFuture.runAsync(() -> {
            this.saveOperationRecords(joinPoint,proceed,fullName,userId);
        });

        return proceed;

    }


    private void saveOperationRecords(ProceedingJoinPoint joinPoint,Object proceed,String fullName,Long userId) {
        try {
            MethodSignature sign = (MethodSignature) joinPoint.getSignature();
            Method method = sign.getMethod();
            OperationPointCut annotation = method.getAnnotation(OperationPointCut.class);
            if (annotation == null) {
                //获取类上的注解
                annotation = joinPoint.getTarget().getClass().getAnnotation(OperationPointCut.class);
                if (annotation == null) {
                    //获取接口上的注解
                    for (Class<?> cls : joinPoint.getClass().getInterfaces()) {
                        annotation = cls.getAnnotation(OperationPointCut.class);
                        if (annotation != null) {
                            break;
                        }
                    }
                }
            }

            String methodName = joinPoint.getSignature().getName();
            Object[] args1 = joinPoint.getArgs();
            ArrayList<Object> objects = Lists.newArrayList();
            for (Object o : args1) {
                if (!(o instanceof BindingResult)) {
                    objects.add(o);
                }
            }
            String args = JSON.toJSONString(objects);

            String module = annotation.module();
            String operation = annotation.operation();
            TbOperationRecords records = new TbOperationRecords();
            records.setCreateName(fullName);
            records.setModule(module);
            records.setOperation(operation);
            records.setCreateBy(userId);
            records.setCreateDate(new Date());
            records.setUpdateBy(userId);
            records.setUpdateDate(new Date());
            records.setMethodName(methodName);
            records.setArgs(args);

            JSONObject o = (JSONObject) JSON.toJSON(proceed);
            Object code = o.get("code");
            int status = 0;
            if (!Objects.isNull(code)) {
                status = Integer.parseInt(String.valueOf(code));
            }
            records.setStatus(status);

            tbOperationRecordsMapper.insert(records);
        } catch (NumberFormatException e) {
            log.error("aop操作日志报错出错,{}",e);
        }
    }

    @AfterThrowing(value = "pointCut()")
    public void methodAfterThrowing(JoinPoint joinPoint) {
    }

}
